#include <jni.h>
#include <string>
#include <jni.h>
#include <string>

#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include "android/log.h"
#include "native-lib.h"

#define TAG "kiayouart"
#define SetLightStateSingle_CMD_LENGTH      8
#define SetLightState_CMD_LENGTH      8
#define InitSubBoardID_CMD_LENGTH      8
unsigned  char InitSubBoardID_CMD[InitSubBoardID_CMD_LENGTH] = {0x01,0x10,0x00,0x00,0x13,0x88,0x12,0x34};
unsigned  char SetLightState_CMD[SetLightState_CMD_LENGTH] = {0x01,0x06,0x00,0x01,0x00,0x00,0x12,0x34};
unsigned  char SetLightStateSingle_CMD[SetLightStateSingle_CMD_LENGTH] = {0x01,0x06,0x00,0x02,0x00,0x00,0x12,0x34};

#define SendMsg_Wish_Head_CMD_LENGTH      14
unsigned char SendMsg_Wish_Head_CMD[SendMsg_Wish_Head_CMD_LENGTH] = {0x01,0x10,0x2C,0x50,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x02,0xff,0xff};//wish:0-3 head,4 data_len,5-6 godID,8-(len-2) data
static int uart_fd;
static pthread_rwlock_t uart_rwlock;
extern "C" JNIEXPORT jstring JNICALL
Java_com_smartlight_godlight_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "来自jni的祝福";
    return env->NewStringUTF(hello.c_str());
}
static speed_t getBaudrate(jint baudrate)
{
    switch(baudrate) {
        case 0: return B0;
        case 50: return B50;
        case 75: return B75;
        case 110: return B110;
        case 134: return B134;
        case 150: return B150;
        case 200: return B200;
        case 300: return B300;
        case 600: return B600;
        case 1200: return B1200;
        case 1800: return B1800;
        case 2400: return B2400;
        case 4800: return B4800;
        case 9600: return B9600;
        case 19200: return B19200;
        case 38400: return B38400;
        case 57600: return B57600;
        case 115200: return B115200;
        case 230400: return B230400;
        case 460800: return B460800;
        case 500000: return B500000;
        case 576000: return B576000;
        case 921600: return B921600;
        case 1000000: return B1000000;
        case 1152000: return B1152000;
        case 1500000: return B1500000;
        case 2000000: return B2000000;
        case 2500000: return B2500000;
        case 3000000: return B3000000;
        case 3500000: return B3500000;
        case 4000000: return B4000000;
        default: return -1;
    }
}

extern "C" JNIEXPORT jobject JNICALL
Java_com_smartlight_godlight_SerialPort_open(JNIEnv *env, jobject thiz, jstring path, jint baudrate, jint flags) {
    speed_t speed;
    jobject mFileDescriptor;
    LOGE("guxing at jni open start");
    /* Check arguments */
    {
        speed = getBaudrate(baudrate);
        if (speed == -1) {
            /* TODO: throw an exception */
            LOGE("native get Invalid baudrate");
            return NULL;
        }
    }
/* Opening device */
    {
        jboolean iscopy;
        const char *path_utf = (*env).GetStringUTFChars(path, &iscopy);
        LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
        uart_fd = open(path_utf, O_RDWR | O_NOCTTY | O_NONBLOCK,0);
        LOGD("open() fd = %d", uart_fd);
        env->ReleaseStringUTFChars(path, path_utf);
        if (uart_fd == -1)
        {
            /* Throw an exception */
            LOGE("Cannot open port %s",path_utf);
            /* TODO: throw an exception */
            return NULL;
        }
    }
/* Configure device */
    {
        struct termios cfg;
        LOGD("Configuring serial port");
        if (tcgetattr(uart_fd, &cfg)){
            LOGE("tcgetattr() failed");
            close(uart_fd);
            /* TODO: throw an exception */
            return NULL;
        }

        cfmakeraw(&cfg);
        cfsetispeed(&cfg, speed);
        cfsetospeed(&cfg, speed);
        if (tcsetattr(uart_fd, TCSANOW, &cfg))
        {
            LOGE("tcsetattr() failed");
            close(uart_fd);
            /* TODO: throw an exception */
            return NULL;
        }
    }
    {
        if (pthread_rwlock_init(&uart_rwlock,NULL) != 0)
        {
            LOGE("uart_rwlock initialization failed.");
        }
    }

    /* Create a corresponding file descriptor */
    {
        jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
        jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
        jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
        mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
        env->SetIntField(mFileDescriptor, descriptorID, (jint)uart_fd);
    }

    return mFileDescriptor;
}

/*
功能：控制所有写号灯的亮灭
参数：
state
	1	: 对应已写码的灯亮
	0	：全灭
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_smartlight_godlight_MainActivity_SendCmdAllLightCtrl(JNIEnv *env, jobject thiz, jint state) {
    int count_i = 0,nwrite = 0,nread = 0;
    char buffer[50] = {0};
    LOGE("-- jni at SendCmdAllLightCtrl, state %d   --",state);

    SetLightState_CMD[5] = state;

    if(uart_fd>0){
        tcflush(uart_fd, TCIOFLUSH);
        pthread_rwlock_wrlock(&uart_rwlock);
        nwrite=write(uart_fd,SetLightState_CMD,SetLightState_CMD_LENGTH);
        pthread_rwlock_unlock(&uart_rwlock);
        usleep(300000);
        if (nwrite > 0){
            LOGE("godlight:SendCmdAllLightCtrl write CMD OK.\n");
        }else{
            LOGE("godlight:SendCmdAllLightCtrl write CMD error.\n");
        }
        for (count_i = 0;count_i < 10;count_i++)
        {
            memset(buffer,'\0',50);
            nread = 0;
            pthread_rwlock_rdlock(&uart_rwlock);
            nread = read(uart_fd,buffer,50);
            pthread_rwlock_unlock(&uart_rwlock);
            LOGE("godlight:read uart .nread = %d .\n",nread);
            if ((nread > 0)&&(buffer[1]==0x06)){
                break;
            }
            //tcflush(uart_fd, TCIOFLUSH);
            //pthread_rwlock_wrlock(&uart_rwlock);
            //nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
            //pthread_rwlock_unlock(&uart_rwlock);
            usleep(300000);
        }
        tcflush(uart_fd, TCIOFLUSH);
        if (count_i < 10) {
            LOGE("godlight:get init board CMD ack OK.count_i = %d .\n",count_i);
            return 1;
        }else{
            LOGE("godlight:get init board CMD ack ERROR.count_i = %d .\n",count_i);
        }
    }
    return 0;
}
/*
功能： 初始化下位机，给分控板写入ID，传入起始地址和需要分配地址的数量即可
参数：
	startid : 起始ID
	Total	: 灯的数量
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_smartlight_godlight_MainActivity_SendCmdInitSubBoardID(JNIEnv *env, jobject thiz, jint startid,
                                                                jint Total) {
    int count_i = 0,nwrite = 0,nread = 0;
    char buffer[50] = {0};
    InitSubBoardID_CMD[2] = startid/256;
    InitSubBoardID_CMD[3] = startid%256;
    InitSubBoardID_CMD[4] = Total/256;
    InitSubBoardID_CMD[5] = Total%256;
    if(uart_fd>0){
        tcflush(uart_fd, TCIOFLUSH);
        pthread_rwlock_wrlock(&uart_rwlock);
        nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
        pthread_rwlock_unlock(&uart_rwlock);
        usleep(300000);
        if (nwrite > 0){
            LOGE("godlight:send sub board id OK,start from %d,Total = %d.nwrite = %d .\n",startid,Total,nwrite);
        }else{
            LOGE("godlight:send sub board id error,start from %d,Total = %d.nwrite = %d .\n",startid,Total,nwrite);
        }
        for (count_i = 0;count_i < 10;count_i++)
        {
            memset(buffer,'\0',50);
            nread = 0;
            pthread_rwlock_rdlock(&uart_rwlock);
            nread = read(uart_fd,buffer,50);
            pthread_rwlock_unlock(&uart_rwlock);
            LOGE("godlight:read uart .nread = %d .\n",nread);
            if ((nread > 0)&&(buffer[3]==0x03)){
                break;
            }
            //tcflush(uart_fd, TCIOFLUSH);
            //pthread_rwlock_wrlock(&uart_rwlock);
            //nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
            //pthread_rwlock_unlock(&uart_rwlock);
            usleep(300000);
        }
        tcflush(uart_fd, TCIOFLUSH);
        if (count_i < 10) {
            LOGE("godlight:get init board CMD ack OK.count_i = %d .\n",count_i);
            return 1;
        }else{
            LOGE("godlight:get init board CMD ack ERROR.count_i = %d .\n",count_i);
        }
    }
    return 0;
}
/*
功能：清屏，即某盏灯的时间到了，需要掐灭
参数：
	godid 灯对应的ID
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_smartlight_godlight_MainActivity_SendCmdClearSingle(JNIEnv *env, jobject thiz, jint godid) {
    int count_i = 0,nwrite = 0,nread = 0;
    char buffer[50] = {0};
    SetLightStateSingle_CMD[4] = godid/256;
    SetLightStateSingle_CMD[5] = godid%256;

    if(uart_fd>0){
        tcflush(uart_fd, TCIOFLUSH);
        pthread_rwlock_wrlock(&uart_rwlock);
        nwrite=write(uart_fd,SetLightStateSingle_CMD,SetLightStateSingle_CMD_LENGTH);
        pthread_rwlock_unlock(&uart_rwlock);
        usleep(300000);
        if (nwrite > 0){
            LOGE("godlight:SendCmdClearSingle write CMD OK,godid %d.\n",godid);
        }else{
            LOGE("godlight:SendCmdClearSingle write CMD ERROR,godid %d.\n",godid);
        }
        for (count_i = 0;count_i < 10;count_i++)
        {
            memset(buffer,'\0',50);
            nread = 0;
            pthread_rwlock_rdlock(&uart_rwlock);
            nread = read(uart_fd,buffer,50);
            pthread_rwlock_unlock(&uart_rwlock);
            LOGE("godlight:read uart .nread = %d .\n",nread);
            if ((nread > 0)&&(buffer[1]==0x06)){
                break;
            }
            //tcflush(uart_fd, TCIOFLUSH);
            //pthread_rwlock_wrlock(&uart_rwlock);
            //nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
            //pthread_rwlock_unlock(&uart_rwlock);
            usleep(300000);
        }
        tcflush(uart_fd, TCIOFLUSH);
        if (count_i < 10) {
            LOGE("godlight:SendCmdClearSingle ACK OK,count_i %d.\n",count_i);
            return 1;
        }else{
            LOGE("godlight:SendCmdClearSingle ACK ERROR,count_i %d.\n",count_i);
        }
    }
    return 0;
}

static int sendmsg_commen_wishstring(JNIEnv *env,jint godid,jint language,jint time,jint money,jint color,jstring namestring,jstring wishstring)
{
    int i = 0;
    int nwrite = 0;
    int count_i = 0,nread = 0;
    char buffer[50] = {0};
    const jchar *namestring_uni = NULL;
    const jchar *wishstring_uni = NULL;
    unsigned int namestring_len = 0;
    unsigned int wishstring_len = 0;
    int lengthMessageWhole = 0;
    char messageBuffer[256] = {0};
    memset(messageBuffer,'\0',256);
    for(i=0;i<SendMsg_Wish_Head_CMD_LENGTH;i++){
        messageBuffer[i]=SendMsg_Wish_Head_CMD[i];
    }
    messageBuffer[4] = godid/256;
    messageBuffer[5] = godid%256;//godid

    messageBuffer[6] = language;

    messageBuffer[7] = time/256;
    messageBuffer[8] = time%256;

    messageBuffer[9] = money/256;
    messageBuffer[10] = money%256;

    messageBuffer[11] = color;
    namestring_uni = env->GetStringChars(namestring,NULL);
    namestring_len = env->GetStringLength(namestring);

    wishstring_uni = env->GetStringChars(wishstring,NULL);
    wishstring_len = env->GetStringLength(wishstring);

    messageBuffer[12] = namestring_len;
    messageBuffer[13] = wishstring_len;

    for(i=0;i<namestring_len;i++){
        messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+i] = namestring_uni[i];
    }
    //memset(namestring_uni,'\0',namestring_len);

    for(i=0;i<wishstring_len;i++){
        messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_len+i] = wishstring_uni[i];
    }
    //memset(wishstring_uni,'\0',wishstring_len);
    messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_len+wishstring_len]=0x12;
    messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_len+wishstring_len+1]=0x34;
    lengthMessageWhole = SendMsg_Wish_Head_CMD_LENGTH+namestring_len+wishstring_len+2;
    pthread_rwlock_wrlock(&uart_rwlock);
    nwrite = write(uart_fd,messageBuffer,lengthMessageWhole);
    pthread_rwlock_unlock(&uart_rwlock);
    if(uart_fd>0){
        tcflush(uart_fd, TCIOFLUSH);
        pthread_rwlock_wrlock(&uart_rwlock);
        nwrite = write(uart_fd,messageBuffer,lengthMessageWhole);
        pthread_rwlock_unlock(&uart_rwlock);
        usleep(300000);
        if (nwrite > 0){
            LOGE("godlight:sendmsg_commen_wishstring write message OK\n");
        }else{
            LOGE("godlight:sendmsg_commen_wishstring write message ERROR\n");
        }
        for (count_i = 0;count_i < 10;count_i++)
        {
            memset(buffer,'\0',50);
            nread = 0;
            pthread_rwlock_rdlock(&uart_rwlock);
            nread = read(uart_fd,buffer,50);
            pthread_rwlock_unlock(&uart_rwlock);
            LOGE("godlight:read uart .nread = %d .\n",nread);
            if ((nread > 0)&&(buffer[3]==0x05)){
                break;
            }
            //tcflush(uart_fd, TCIOFLUSH);
            //pthread_rwlock_wrlock(&uart_rwlock);
            //nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
            //pthread_rwlock_unlock(&uart_rwlock);
            usleep(300000);
        }
        tcflush(uart_fd, TCIOFLUSH);
        if (count_i < 10) {
            LOGE("godlight:sendmsg_commen_wishstring ACK OK,count_i %d.\n",count_i);
            return 1;
        }else{
            LOGE("godlight:sendmsg_commen_wishstring ACK ERROR,count_i %d.\n",count_i);
        }
    }
    return 0;
}
static int sendmsg_CN_wishstring(JNIEnv *env,jint godid,jint language,jint time,jint money,jint color,jstring namestring,jstring wishstring)
{
    const jchar *namestring_uni = NULL;
    unsigned int namestring_len = 0;
    unsigned int namestring_uni_len = 0;

    const jchar *wishstring_uni = NULL;
    unsigned int wishstring_len = 0;
    unsigned int wishstring_uni_len = 0;
    unsigned int i=0,j=0;
    char unitocmsg[140] = {0};
    char messageBuffer[256] = {0};
    int lengthMessageWhole = 0;
    int nwrite = 0;
    int nread = 0;
    int count_i = 0;
    char buffer[50] = {0};

    memset(messageBuffer,'\0',256);
    for(i=0;i<SendMsg_Wish_Head_CMD_LENGTH;i++){
        messageBuffer[i]=SendMsg_Wish_Head_CMD[i];
    }
    messageBuffer[4] = godid/256;
    messageBuffer[5] = godid%256;//godid

    messageBuffer[6] = language;

    messageBuffer[7] = time/256;
    messageBuffer[8] = time%256;

    messageBuffer[9] = money/256;
    messageBuffer[10] = money%256;

    messageBuffer[11] = color;

    namestring_uni = env->GetStringChars(namestring,NULL);//get unicode
    namestring_len = env->GetStringLength(namestring);
    namestring_uni_len = namestring_len*2;

    wishstring_uni = env->GetStringChars(wishstring,NULL);//get unicode
    wishstring_len = env->GetStringLength(wishstring);
    wishstring_uni_len = wishstring_len*2;

    messageBuffer[12] = namestring_len;
    messageBuffer[13] = wishstring_len;

    for(i=0; i<namestring_len; i++){//jchar to char
        j=2*i;
        if(((namestring_uni[i] & 0xff00)>>8)>0){
            unitocmsg[j] = (namestring_uni[i] & 0xff00)>>8;
            unitocmsg[j+1] = namestring_uni[i] & 0xff;
        }else{
            unitocmsg[j] = 0x00;
            unitocmsg[j+1] = namestring_uni[i] & 0xff;
        }
    }
    for(i=0;i<namestring_uni_len;i++){
        messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+i] = unitocmsg[i];
    }
    memset(unitocmsg,'\0',namestring_uni_len);

    for(i=0; i<wishstring_len; i++){//jchar to char
        j=2*i;
        if(((wishstring_uni[i] & 0xff00)>>8)>0){
            unitocmsg[j] = (wishstring_uni[i] & 0xff00)>>8;
            unitocmsg[j+1] = wishstring_uni[i] & 0xff;
        }else{
            unitocmsg[j] = 0x00;
            unitocmsg[j+1] = wishstring_uni[i] & 0xff;
        }
    }
    LOGE("-- get msg unitocmsg %d   %x,%x,  %x,%x,  %x,%x --",wishstring_len,unitocmsg[0],unitocmsg[1],unitocmsg[2],unitocmsg[3],unitocmsg[4],unitocmsg[5]);

    for(i=0;i<wishstring_uni_len;i++){
        messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_uni_len+i] = unitocmsg[i];
    }
    memset(unitocmsg,'\0',wishstring_uni_len);

    messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_uni_len+wishstring_uni_len]=0x12;
    messageBuffer[SendMsg_Wish_Head_CMD_LENGTH+namestring_uni_len+wishstring_uni_len+1]=0x34;
    lengthMessageWhole = SendMsg_Wish_Head_CMD_LENGTH+namestring_uni_len+wishstring_uni_len+2;

    if(uart_fd>0){
        tcflush(uart_fd, TCIOFLUSH);
        pthread_rwlock_wrlock(&uart_rwlock);
        nwrite = write(uart_fd,messageBuffer,lengthMessageWhole);
        pthread_rwlock_unlock(&uart_rwlock);
        usleep(300000);
        if (nwrite > 0){
            LOGE("godlight:sendmsg_commen_wishstring write message OK\n");
        }else{
            LOGE("godlight:sendmsg_commen_wishstring write message ERROR\n");
        }
        for (count_i = 0;count_i < 10;count_i++)
        {
            memset(buffer,'\0',50);
            nread = 0;
            pthread_rwlock_rdlock(&uart_rwlock);
            nread = read(uart_fd,buffer,50);
            pthread_rwlock_unlock(&uart_rwlock);
            LOGE("godlight:read uart .nread = %d .\n",nread);
            if ((nread > 0)&&(buffer[3]==0x05)){
                    break;
            }
            //tcflush(uart_fd, TCIOFLUSH);
            //pthread_rwlock_wrlock(&uart_rwlock);
            //nwrite=write(uart_fd,InitSubBoardID_CMD,InitSubBoardID_CMD_LENGTH);
            //pthread_rwlock_unlock(&uart_rwlock);
            usleep(300000);
        }
        tcflush(uart_fd, TCIOFLUSH);
        if (count_i < 10) {
            LOGE("godlight:sendmsg_commen_wishstring ACK OK,count_i %d.\n",count_i);
            return 1;
        }else{
            LOGE("godlight:sendmsg_commen_wishstring ACK ERROR,count_i %d.\n",count_i);
        }
    }
    return 0;
}
/*
功能：发送相关信息到下位机
根据语言选择不同的形式发送，中文为一类，其他语言为一类
godid 		:	对应ID
name		:	对应的名字
money		:	对应金额
wishstring	:	祝福语
color		:	颜色	0x01 红色，0x02 橙色 0x03 黄色 0x04 绿色 0x05 蓝色 0x06 蓝紫 0x07 紫色
language	:	语言	0x01 中文，0x02 英文，后续其他语言编码做统一分配
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_smartlight_godlight_MainActivity_SendMessage(JNIEnv *env, jobject thiz, jint godid,
                                                      jstring name,jint time, jint money, jstring wishstring,
                                                      jint color,jint language) {
    //LOGE("--guixing at jni , SendMessage");
    if(language==1){
        sendmsg_CN_wishstring(env,godid,language,time,money,color,name,wishstring);
    }else{
        sendmsg_commen_wishstring(env,godid,language,time,money,color,name,wishstring);
    }

    return 0;
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_smartlight_godlight_MainActivity_SendCmdLightCtrl(JNIEnv *env, jobject thiz, jint lgithid,
                                                           jint state) {

    return 0;
}
